package com.example.exceldemo.liteflowComponent.common;

import cn.hutool.core.io.FileUtil;
import com.alibaba.excel.util.StringUtils;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import com.example.exceldemo.constants.DocConstants;
import com.example.exceldemo.doc.DocGenUtil;
import com.example.exceldemo.exception.BizException;
import com.example.exceldemo.model.DemoContext;
import com.example.exceldemo.model.FunctionInfoDTO;
import com.example.exceldemo.model.ReqInfoDTO;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.NodeComponent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 文档生成基础组件
 * <p>
 * 提供文档生成的通用功能，包括处理需求信息、准备输出目录等
 * </p>
 *
 * @author system
 */
@Slf4j
@LiteflowComponent("generate")
public abstract class GenerateDocuments extends NodeComponent {

    /**
     * 表格循环渲染策略
     */
    private LoopRowTableRenderPolicy policy;

    /**
     * 配置参数
     */
    protected Map<String, String> settings;

    /**
     * 处理流程
     * <p>
     * 处理每个需求并生成相应的文档
     * </p>
     *
     * @throws Exception 如果处理过程中发生错误
     */
    @Override
    public void process() throws Exception {
        log.info("开始生成文档");
        DemoContext context = this.getContextBean(DemoContext.class);
        settings = context.getSettings();
        String outputDirPath = context.getOutputDirPath();
        List<ReqInfoDTO> reqInfoList = context.getReqInfoDTOS();
        String templateDir = context.getTemplateDir();
        
        if (CollectionUtils.isEmpty(reqInfoList)) {
            log.warn("没有需求数据需要处理");
            return;
        }
        
        reqInfoList.forEach(reqInfo -> {
            try {
                // 需求数据完整性检查 - 跳过无效的需求数据
                if (!DocGenUtil.isValidReqInfo(reqInfo)) {
                    log.warn("需求数据不完整，跳过处理: {}", reqInfo.getReqNo());
                    return;
                }
                
                String reqOutputDir = prepareOutputDirectory(reqInfo, outputDirPath);
                processReqDocuments(reqInfo, templateDir, reqOutputDir, settings);
                log.info("需求 {} 文档生成成功", reqInfo.getReqNo());
            } catch (Exception e) {
                // 异常处理：记录错误但不中断整个处理流程
                log.error("处理需求时出错: {} - {}, 错误: {}",
                        Optional.ofNullable(reqInfo).map(ReqInfoDTO::getReqNo).orElse("未知"),
                        Optional.ofNullable(reqInfo).map(ReqInfoDTO::getReqName).orElse("未知"),
                        e.getMessage(), e);
            }
        });
        
        log.info("文档生成完成");
    }

    /**
     * 处理单个需求的文档生成
     * <p>
     * 由子类实现具体的文档生成逻辑
     * </p>
     *
     * @param reqInfo 需求信息
     * @param templateDir 模板目录
     * @param outputDirPath 输出目录
     * @param settings 设置参数
     */
    public abstract void processReqDocuments(ReqInfoDTO reqInfo, String templateDir, String outputDirPath, Map<String, String> settings);

    /**
     * 获取文档名称
     * <p>
     * 由子类实现具体的文档命名逻辑
     * </p>
     *
     * @param reqInfo 需求信息
     * @return 文档名称
     */
    public abstract String getDocName(ReqInfoDTO reqInfo);

    /**
     * 获取上下文
     *
     * @return 上下文对象
     */
    public DemoContext getDemoContext() {
        return this.getContextBean(DemoContext.class);
    }

    /**
     * 处理功能列表信息
     * <p>
     * 解析需求中的功能列表，转换为功能信息对象列表
     * </p>
     *
     * @param reqInfo 需求信息
     * @return 功能列表
     */
    public List<FunctionInfoDTO> processFunctionList(ReqInfoDTO reqInfo) {
        // 检查功能列表是否为空，如果为空则添加默认功能
        if (StringUtils.isBlank(reqInfo.getFunctionList())) {
            log.warn("需求 {} 没有功能列表，将使用默认功能", reqInfo.getReqNo());
            reqInfo.setFunctionList(DocConstants.Function.DEFAULT_FUNCTION);
        }

        // 解析并构建功能列表对象
        List<FunctionInfoDTO> functionList = new ArrayList<>();
        String[] functionListStr = reqInfo.getFunctionList().split(DocConstants.Function.SEPARATOR);
        String developer = Optional.ofNullable(reqInfo.getReqDeveloper()).orElse("");

        AtomicInteger counter = new AtomicInteger(1);

        for (String functionStr : functionListStr) {
            if (StringUtils.isBlank(functionStr)) {
                continue;
            }
            
            String[] funDescs = functionStr.split(DocConstants.Function.DESC_SEPARATOR);
            FunctionInfoDTO functionInfoDTO = new FunctionInfoDTO();

            functionInfoDTO.setCode(String.valueOf(counter.getAndIncrement()));
            functionInfoDTO.setName(functionStr.trim());
            functionInfoDTO.setDesc(functionStr.trim());

            if (funDescs.length > 1) {
                functionInfoDTO.setName(funDescs[0].trim());
                functionInfoDTO.setDesc(funDescs[1].trim());
            }

            functionInfoDTO.setDeveloper(developer);
            functionInfoDTO.setSystem(DocConstants.Function.DEFAULT_SYSTEM);
            functionList.add(functionInfoDTO);
        }

        return functionList;
    }

    /**
     * 获取表格渲染策略
     * <p>
     * 懒加载方式获取表格渲染策略实例
     * </p>
     *
     * @return 表格渲染策略
     */
    public LoopRowTableRenderPolicy getPolicy() {
        if (policy == null) {
            policy = new LoopRowTableRenderPolicy();
        }
        return policy;
    }

    /**
     * 创建基础配置
     * <p>
     * 创建文档模板渲染的基础配置
     * </p>
     *
     * @param policy 表格循环渲染策略
     * @return 配置对象
     */
    public Configure createBaseConfig(LoopRowTableRenderPolicy policy) {
        return Configure.builder()
                .bind("functionList", policy)
                .bind("terms", policy)
                .bind("testCases", policy)
                .build();
    }

    /**
     * 准备输出目录
     * <p>
     * 为每个需求创建独立的输出子目录
     * </p>
     *
     * @param reqInfo 需求信息
     * @param outputDirPath 根输出目录
     * @return 创建好的输出目录路径
     * @throws BizException 如果需求信息不完整或无法创建目录
     */
    private String prepareOutputDirectory(ReqInfoDTO reqInfo, String outputDirPath) {
        if (reqInfo == null || StringUtils.isBlank(reqInfo.getReqNo())) {
            throw BizException.docGenerateError("需求信息不完整，无法创建输出目录");
        }
        
        // 为每个需求创建独立的输出子目录
        Path filePath = Paths.get(outputDirPath, reqInfo.getReqNo() + reqInfo.getReqName());
        String outputDir = filePath.toString();

        // 检查并创建输出目录
        if (!FileUtil.exist(outputDir)) {
            File created = FileUtil.mkdir(outputDir);
            if (created == null) {
                throw BizException.docGenerateError("创建需求输出目录失败: " + outputDir);
            }
            log.info("创建输出子目录: {}", outputDir);
        }

        return outputDir;
    }
}
